﻿using System;
using System.Collections.Generic;
using System.Text;

using Atosenet.Protocol;


namespace Atosenet.IO
{
    public class LinkManager
    {
        #region 成员

        public event LinkStatusChangedEventHandler LinkStatusChanged;
        public event IODataGeneratedEventHandler IODataGenerated;
        public event IOLinkPacketReceivedEventHandler PacketReceived;

        #endregion


        #region 初始化

        public LinkManager()
        {
            DataLinks = new LinkCollection();
        }

        public bool Initialize(PipelinePool parent)
        {
            Parent = parent;
            return true;
        }

        #endregion


        #region 公开函数

        public bool SendTo(int linkId, int hostId, ProtocolPacket pkt)
        {
            IOLink link = DataLinks.Find((l) => { return l.LinkID == linkId && l.HostID == hostId; });
            return link != null ? link.SendPacket(pkt) : false;
        }

        public bool SendTo(int linkId, int hostId, byte[] data)
        {
            IOLink link = DataLinks.Find((l) => { return l.LinkID == linkId && l.HostID == hostId; });
            return link != null ? link.SendData(data) : false;
        }

        public bool ReceiveFrom(int linkId, int hostId, byte[] data)
        {
            IOLink link = DataLinks.Find((l) => { return l.LinkID == linkId && l.HostID == hostId; });
            return link != null ? link.InputData(data) : false;
        }

        public bool AddLink(int linkId, string protocolType)
        {
            return AddLink(linkId, linkId, protocolType);
        }

        public bool AddLink(int linkId, int hostId, string protocolType)
        {
            IOLink link = new IOLink();
            link.Initialize(linkId, hostId, protocolType);
            link.InputDataGenerated += Link_InputDataGenerated;
            link.IOLinkStatusChanged += Link_IOLinkStatusChanged;
            link.PacketReceived += Link_PacketReceived;

            if (DataLinks.Exists((l) => { return l.LinkID == linkId; }))
                return false;

            DataLinks.Add(link);
            return true;
        }

        public bool RemoveLink(int linkId, int hostId)
        {
            IOLink link = DataLinks.Find((l) => { return l.LinkID == linkId && l.HostID == hostId; });

            if (link != null)
            {
                link.Stop();
                link.InputDataGenerated -= Link_InputDataGenerated;
                link.IOLinkStatusChanged -= Link_IOLinkStatusChanged;
                link.PacketReceived -= Link_PacketReceived;
                DataLinks.Remove(link);
                return true;
            }
            return false;
        }

        public bool Start(int linkId, int hostId)
        {
            IOLink link = DataLinks.Find((l) => { return l.LinkID == linkId && l.HostID == hostId; });
            return link != null ? link.Start() : false;
        }

        public bool Stop(int linkId, int hostId)
        {
            IOLink link = DataLinks.Find((l) => { return l.LinkID == linkId && l.HostID == hostId; });
             return link != null ? link.Stop() : false;
        }

        public bool StartAll(out int started)
        {
            started = StartAll();
            return DataLinks.Count == StartedCount;
        }

        public int StartAll()
        {
            int count = 0;

            foreach (IOLink io in DataLinks)
                count = io.Start() ? count + 1 : count;

            return count;
        }

        public bool StopAll(out int stopped)
        {
            stopped = StopAll();
            return DataLinks.Count == StartedCount;
        }

        public int StopAll()
        {
            int count = 0;

            foreach (IOLink io in DataLinks)
                count = io.Stop() ? count + 1 : count;

            return count;
        }

        #endregion


        #region 静态函数



        #endregion


        #region 核心函数

        private void Link_PacketReceived(object sender, ProtocolPacketReceivedEventArgs e)
        {
            IOLink iLink = DataLinks.Find(link => { return link.LinkID == e.LinkID && link.HostID == e.HostID; });

            if (iLink == null)
                return;

            if (PacketReceived != null)
            {
                IProtocolPacket[] pkts = iLink.GetAllPackets();

                //IProtocolPacket pk = null;
                //iLink.GetOnePacket(out pk);
                //System.Threading.Thread.Sleep(1000);
                //IProtocolPacket[] pkts = new IProtocolPacket[] { pk };

                IOLinkPacketReceivedEventArgs ee = new IOLinkPacketReceivedEventArgs(e.LinkID, e.HostID, pkts, e.Timestamp);
                PacketReceived(this, ee);
            }
        }

        private void Link_IOLinkStatusChanged(object sender, IOLinkStatusChangedEventArgs e)
        {
            if (LinkStatusChanged != null)
            {
                LinkStatusChangedEventArgs ee = new LinkStatusChangedEventArgs(e.Status, e.LinkID, e.HostID, e.Timestamp);
                LinkStatusChanged(this, ee);
            }
        }

        private void Link_InputDataGenerated(object sender, InputDataGeneratedEventArgs e)
        {
            if (IODataGenerated != null)
            {
                IODataGeneratedEventArgs ee = new IODataGeneratedEventArgs(e.Data, e.LinkID, e.HostID, e.Timestamp);
                IODataGenerated(this, ee);
            }
        }

        #endregion


        #region 属性

        private PipelinePool Parent
        {
            get;
            set;
        }

        public bool IsInitialized
        {
            get { return Parent != null; }
        }

        public LinkCollection DataLinks
        {
            get;
            private set;
        }

        public int StartedCount
        {
            get
            {
                int count = 0;

                foreach (IOLink io in DataLinks)
                    count = io.IsStarted ? count + 1 : count;

                return count;
            }
        }

        public int StoppedCount
        {
            get
            {
                int count = 0;

                foreach (IOLink io in DataLinks)
                    count = !io.IsStarted ? count + 1 : count;

                return count;
            }
        }

        #endregion


        #region 附加对象

        public class LinkCollection : BaseCollection<IOLink>
        {
            #region 初始化

            public LinkCollection()
                : base()
            { }

            #endregion


            #region 核心函数

            protected override void InsertItem(int index, IOLink item)
            {
                if (this.Exists((link) => { return link.LinkID == item.LinkID; }))
                    return;

                base.InsertItem(index, item);
            }

            #endregion
        }

        #endregion
    }


    public delegate void IOLinkPacketReceivedEventHandler(object sender, IOLinkPacketReceivedEventArgs e);

    public class IOLinkPacketReceivedEventArgs : EventArgs
    {
        public DateTime Timestamp;
        public int LinkID;
        public int HostID;
        public IProtocolPacket[] Packets;

        public IOLinkPacketReceivedEventArgs(int linkId, int hostId, IProtocolPacket[] packets, DateTime timestamp)
        {
            HostID = hostId;
            Timestamp = timestamp;
            LinkID = linkId;
            Packets = packets;
        }
    }

    public delegate void LinkStatusChangedEventHandler(object sender, LinkStatusChangedEventArgs e);

    public class LinkStatusChangedEventArgs : EventArgs
    {
        public IOLinkStatus Status;
        public int LinkID;
        public int HostID;
        public DateTime Timestamp;

        public LinkStatusChangedEventArgs(IOLinkStatus status, int linkId, int hostId, DateTime time)
        {
            HostID = hostId;
            LinkID = linkId;
            Status = status;
            Timestamp = time;
        }

        public bool IsClient
        {
            get { return LinkID != HostID; }
        }
    }
    
    public delegate void IODataGeneratedEventHandler(object sender, IODataGeneratedEventArgs e);

    public class IODataGeneratedEventArgs : EventArgs
    {
        public byte[] Data;
        public int LinkID;
        public int HostID;
        public DateTime Timestamp;

        public IODataGeneratedEventArgs(byte[] data, int id, int hostId, DateTime time)
        {
            HostID = hostId;
            Data = data;
            LinkID = id;
            Timestamp = time;
        }

        public bool IsClient
        {
            get { return LinkID != HostID; }
        }
    }
}
